Preserve element type for mvcombine ARRAY_AGG on the DataFusion route - #22617
Preserve element type for mvcombine ARRAY_AGG on the DataFusion route#22617noCharger wants to merge 1 commit into
Conversation
PR Reviewer Guide 🔍(Review updated until commit f6cfd03)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to f6cfd03 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 7fbfc40
Suggestions up to commit f6cfd03
Suggestions up to commit 5dc833e
Suggestions up to commit 6fc048c
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #22617 +/- ##
============================================
- Coverage 71.42% 71.40% -0.02%
- Complexity 76786 76789 +3
============================================
Files 6148 6148
Lines 357980 357980
Branches 52177 52177
============================================
- Hits 255689 255624 -65
- Misses 81937 82033 +96
+ Partials 20354 20323 -31 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6fc048c to
5dc833e
Compare
|
Persistent review updated to latest commit 5dc833e |
|
❌ Gradle check result for 5dc833e: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
PPL mvcombine lowers to Calcite ARRAY_AGG. On the analytics-engine (DataFusion) route this failed with "No enum constant ...ARRAY_AGG" (the aggregate was not recognized), and mapping it onto the existing list()/values() array-agg operator would stringify elements to VARCHAR (that operator casts to VARCHAR by design for the list()/values() multivalue-string contract). Add a dedicated type-preserving path so the collected array keeps the source element type (ARRAY<INT>, not ARRAY<VARCHAR>): - AggregateFunction.fromNameOrError: recognize ARRAY_AGG as the LIST (collect-into-array) family for backend viability and the STATE_EXPANDING decomposition. - DataFusionFragmentConvertor: add LOCAL_ARRAY_AGG_TYPED_OP whose return type is derived from the operand and which does not cast to VARCHAR; it drops null elements (matching ARRAY_AGG ... FILTER (IS NOT NULL)) via filtersNullArgs, and maps to the same type-generic DataFusion array_agg UDAF. - PplAggregateCallRewriter: route ARRAY_AGG to the typed op for the PARTIAL/SINGLE stage and to the existing type-generic list_merge for the FINAL merge. list()/values() are unchanged (still ARRAY<VARCHAR>). No Rust change: the array_agg/list_merge UDAFs already derive the element type. Signed-off-by: Louis Chu <lingzhichu.clz@gmail.com>
5dc833e to
f6cfd03
Compare
|
Persistent review updated to latest commit f6cfd03 |
|
Persistent review updated to latest commit 7fbfc40 |
|
❌ Gradle check result for 7fbfc40: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
7fbfc40 to
f6cfd03
Compare
|
Persistent review updated to latest commit f6cfd03 |
Description
PPL
mvcombinelowers to CalciteARRAY_AGG. On the analytics-engine (DataFusion) route this currently fails withNo enum constant org.opensearch.analytics.spi.AggregateFunction.ARRAY_AGG— the aggregate is not recognized. Mapping it onto the existinglist()/values()array-agg operator is not correct either: that operator casts every element to VARCHAR by design (the PPLlist()/values()multivalue-string contract), somvcombineover a non-string field would returnARRAY<VARCHAR>instead of preserving the source type.This adds a dedicated type-preserving path so the collected array keeps the source element type (e.g.
ARRAY<INT>, notARRAY<VARCHAR>):AggregateFunction.fromNameOrError— recognizeARRAY_AGGas theLIST(collect-into-array) family for backend viability and theSTATE_EXPANDINGdecomposition. Element typing is handled separately in the rewriter, so this mapping only affects viability/decomposition shape.DataFusionFragmentConvertor— addLOCAL_ARRAY_AGG_TYPED_OP, aLocalAggOpwhose return type is derived from the operand (not hardcoded VARCHAR) and which does not cast the element. It drops null elements (matchingARRAY_AGG ... FILTER (IS NOT NULL)) viafiltersNullArgs, and maps to the same type-generic DataFusionarray_aggUDAF asLOCAL_ARRAY_AGG_OP.PplAggregateCallRewriter— routeARRAY_AGGto the typed op for the PARTIAL/SINGLE stage, and to the existing (already type-generic)list_mergefor the FINAL merge.list()/values()are unchanged (stillARRAY<VARCHAR>). No Rust change — thearray_agg/list_mergeUDAFs already derive the element type from the input.Verified on the DataFusion route (composite/parquet index,
analytics.planner.prefer_metadata_driver=false):source=<idx> | fields category, age | mvcombine ageover an integer field returns unquoted integers ([30, 30],[25, 35],[40]) with the query profile reportingchosen_backend=datafusion;list()/values()still returnARRAY<VARCHAR>.Related Issues
Enables
mvcombineon the analytics-engine (DataFusion) route. Themvcombinecommand lives in the SQL plugin (opensearch-project/sql#4766).Check List
AggregateFunctionTests#testArrayAggResolvesToList—ARRAY_AGGresolves to theLISTfamily.DataFusionFragmentConvertorTests#testAttachFragmentOnTop_ArrayAggOverScalar_MeasureArgIsRawFieldNotVarcharCast— the substrait measure arg is the raw field, not a VARCHAR cast (the type-preservation guarantee).--signoff.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.